home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
PC World Komputer 2010 April
/
PCWorld0410.iso
/
pluginy Firefox
/
1833
/
1833.xpi
/
modules
/
yoonoCommandQueue.js
< prev
next >
Wrap
Text File
|
2009-12-16
|
15KB
|
503 lines
var EXPORTED_SYMBOLS = ["commandQueueMgr"];
Components.utils.import("resource://yoono/yoonoPrefs.js");
// Yoono stuff
var yoono = {};
var log = {info:function() {},debug:function() {},warn:function(){},error:function (){},fatal:function(){}};
// Vars
const YOONO_DIR = "yoono";
const SYNC_FILE = "yoono_commands.log";
const SYNC_RUNNING_FILE = "yoono_running_commands.log";
// Globals
const CI = Components.interfaces;
const CL = Components.classes;
const DIRSERVICE = CL['@mozilla.org/file/directory_service;1'].getService(CI.nsIProperties);
const PREFSSERVICE = CL["@mozilla.org/preferences-service;1"].getService(CI.nsIPrefService);
const PREFS = PREFSSERVICE.getBranch("extensions.yoono.");
const REQUEST_DELAY = 1000; // en ms.
//**************************************************************************/
//
// All request can now pile up but only transactional are saved over sessions
//
function CommandQueue() {
this.wrappedJSObject=this;
this._nextTransactionFile = DIRSERVICE.get("ProfDS", CI.nsIFile);
this._runningTransactionFile = DIRSERVICE.get("ProfDS", CI.nsIFile);
this._nextTransactionFile.append(YOONO_DIR); this._nextTransactionFile.append(SYNC_FILE);
this._runningTransactionFile.append(YOONO_DIR); this._runningTransactionFile.append(SYNC_RUNNING_FILE);
this._running=[];
this._next=[];
this.isRunning=false;
this._observers=[];
}
CommandQueue.prototype.init = function (y) {
yoono = y;
log = y.log;
try {
// Releases before 3.0.6 wrote the sync file in the user chrome directory
// Newer releases write the sync file in the yoono directory
// If the file exists at the old location, move it first
var oldFile = DIRSERVICE.get("UChrm", CI.nsIFile);
oldFile.append(SYNC_FILE);
if (oldFile.exists()) {
var newFile = DIRSERVICE.get('ProfDS', CI.nsIFile);
newFile.append(YOONO_DIR);
oldFile.moveTo(newFile,SYNC_FILE);
}
this.reload();
} catch(e) {
log.exception(e);
}
}
CommandQueue.prototype.uninstall = function() {
try {
log.warn("Remove sync-file");
var file = DIRSERVICE.get("UChrm", CI.nsIFile);
file.append(SYNC_FILE);
if( file.exists() ) {
file.remove(true);
}
} catch(e) {}
try {
file = DIRSERVICE.get("ProfDS", CI.nsIFile);
file.append(YOONO_DIR);
file.append(SYNC_FILE);
if( file.exists() ) {
file.remove(true);
}
} catch(e) {}
try {
file = DIRSERVICE.get("ProfDS", CI.nsIFile);
file.append(YOONO_DIR);
file.append(SYNC_RUNNING_FILE);
if( file.exists() ) {
file.remove(true);
}
} catch(e) {}
}
// Load commands from command file from last session.
CommandQueue.prototype.reload = function() {
var start = (new Date()).getTime();
var istream = CL["@mozilla.org/network/file-input-stream;1"].createInstance(CI.nsIFileInputStream);
// Reload next requests
if( this._nextTransactionFile.exists() ) {
try {
istream.init(this._nextTransactionFile, 0x01, 0444, 0);
var converter = CL["@mozilla.org/intl/converter-input-stream;1"].createInstance( CI.nsIConverterInputStream);
converter.init(istream, 'UTF-8', 1024, '-');
var line = {};
this._next = [];
var content="";
while(converter.readString(4096, line)) {
content+=line.value;
}
var requests=content.split('\n');
for each(var r in requests) {
if (r.length<=3) continue;
this._next.push( new XML(r) );
}
istream.close();
} catch(e) {
log.exception(e);
var outputStream = CL["@mozilla.org/network/file-output-stream;1"].createInstance( CI.nsIFileOutputStream);
outputStream.init(this._nextTransactionFile, 0x02 | 0x08 | 0x20 , 0644, 0);
outputStream.write("", 0);
outputStream.flush();
outputStream.close();
}
}
// Reload running requests
if( this._runningTransactionFile.exists() ) {
try {
istream.init(this._runningTransactionFile, 0x01, 0444, 0);
var converter = CL["@mozilla.org/intl/converter-input-stream;1"].createInstance( CI.nsIConverterInputStream);
converter.init(istream, 'UTF-8', 1024, '-');
var line = {};
this._running = [];
var content="";
while(converter.readString(4096, line)) {
content+=line.value+"\n";
}
var requests=content.split('\n');
for each(var r in requests) {
if (r.length<=3) continue;
this._running.push( new XML(r) );
}
istream.close();
} catch(e) {
log.exception(e);
var outputStream = CL["@mozilla.org/network/file-output-stream;1"].createInstance( CI.nsIFileOutputStream);
outputStream.init(this._runningTransactionFile, 0x02 | 0x08 | 0x20 , 0644, 0);
outputStream.write("", 0);
outputStream.flush();
outputStream.close();
}
}
log.debug("reload elapse-time = "+ ((new Date()).getTime() - start));
this.flush();
}
// Simulate a browser shutdown for unit testing
CommandQueue.prototype.simulateShutdown = function() {
this._running=[];
this._next=[];
}
// Reset all list : in-memory and files
// used mainly by unit testing
CommandQueue.prototype.fullReset = function() {
this._running=[];
var outputStream = CL["@mozilla.org/network/file-output-stream;1"].createInstance( CI.nsIFileOutputStream);
outputStream.init(this._runningTransactionFile, 0x02 | 0x08 | 0x20 , 0644, 0);
outputStream.write("", 0);
outputStream.flush();
outputStream.close();
this._next=[];
var outputStream = CL["@mozilla.org/network/file-output-stream;1"].createInstance( CI.nsIFileOutputStream);
outputStream.init(this._nextTransactionFile, 0x02 | 0x08 | 0x20 , 0644, 0);
outputStream.write("", 0);
outputStream.flush();
outputStream.close();
}
// Register a new observer to handle responses and errors
// observer = {onSendingRequest:function(request){}, onRequestSuccess:function(request, response){return newRequest;}, onRequestError:function(request){}}
// if onRequestSuccess return a request (string), it is added to the current request and resent
CommandQueue.prototype.addObserver = function(o) {
this._observers.push(o);
}
CommandQueue.prototype.removeObserver = function(o) {
for(i=0;i<this._observers.length;i++){
if(o==this._observers[i]) this._observers.splice(i, 1);
}
}
// Request which must absolutely be sent
// (equivalent of persistant next in old API)
CommandQueue.prototype.addTransactionalRequest = function (s) {
log.debug("Adding transactional request : "+s.toXMLString());
// Add to in-memory list
this._next.push(s)
// Add to transaction file
var outputStream = CL["@mozilla.org/network/file-output-stream;1"].createInstance( CI.nsIFileOutputStream);
var converter = CL['@mozilla.org/intl/converter-output-stream;1'].createInstance(CI.nsIConverterOutputStream);
converter.init(outputStream, 'UTF-8', 1024, '-');
// WRONLY, CREATE_FILE, TRUNCATE
// from http://lxr.mozilla.org/aviary101branch/source/nsprpub/pr/include/prio.h
outputStream.init(this._nextTransactionFile, 0x02 | 0x08 | 0x10 , 0644, 0);
converter.writeString(s.toXMLString().replace(/\n/g,"")+"\n");
converter.flush();
outputStream.flush();
outputStream.close();
// Flush requests
this.flush();
}
// All other requests which doesn't need to be keept over session
// (equivalent of transcient next)
CommandQueue.prototype.addTranscientRequest = function (s) {
var strCmd = s.toXMLString();
log.debug("Adding transcient request : " + strCmd);
// if connect command, remove any previous connect commands...
if(0 == strCmd.indexOf('<connect')) {
var nb = this._next.length;
for(var idx=nb-1; idx >= 0; idx --) {
var tr = this._next[idx];
strCmd = tr.toXMLString();
if(0 == strCmd.indexOf('<connect')) {
this._next.splice(idx, 1);
}
}
}
this._next.push(s);
this.flush();
}
// Replace current running requests with this one in order to run before next commands
// (equivalent of transcient running with clearRunninCommands)
CommandQueue.prototype._replaceRunningRequest = function (s) {
log.debug("Replace request to the running one : "+s.toXMLString());
this._running=[s];
}
// Return the next request to send
CommandQueue.prototype._getRequest = function () {
if (this._running.length==0) { // switch next requests to running ones
log.debug("Switch requests");
// 1) write next into running
// Switch in-memory lists
this._running=this._next;
// Write next into running transaction file
var outputStream = CL["@mozilla.org/network/file-output-stream;1"].createInstance( CI.nsIFileOutputStream);
var converter = CL['@mozilla.org/intl/converter-output-stream;1'].createInstance(CI.nsIConverterOutputStream);
converter.init(outputStream, 'UTF-8', 1024, '-');
// WRONLY, CREATE_FILE, TRUNCATE
// from http://lxr.mozilla.org/aviary101branch/source/nsprpub/pr/include/prio.h
outputStream.init(this._runningTransactionFile, -1, 0644, 0);
converter.writeString(this._next.map(function (r){return r.toXMLString().replace(/\n/g,"");}).join('\n')+"\n");
converter.flush();
outputStream.flush();
outputStream.close();
// 2) clean up next
// Clean in-memory
this._next=[];
// Clean next transaction file
var outputStream = CL["@mozilla.org/network/file-output-stream;1"].createInstance( CI.nsIFileOutputStream);
outputStream.init(this._nextTransactionFile, 0x02 | 0x08 | 0x20 , 0644, 0);
outputStream.write("", 0);
outputStream.flush();
outputStream.close();
} else {
log.debug("Redo current request");
}
return this._running;
}
CommandQueue.prototype._switchToNextRequests = function () {
this._running=[];
var outputStream = CL["@mozilla.org/network/file-output-stream;1"].createInstance( CI.nsIFileOutputStream);
outputStream.init(this._runningTransactionFile, 0x02 | 0x08 | 0x20 , 0644, 0);
outputStream.write("", 0);
outputStream.flush();
outputStream.close();
}
CommandQueue.prototype.isEmpty = function() {
return (this._next.length == 0 && this._running.length == 0);
}
CommandQueue.prototype._timer = CL['@mozilla.org/timer;1'].createInstance(CI.nsITimer);
// Wait in order to aggregate some requests and try to send
CommandQueue.prototype.flush = function () {
if (this.isRunning)
return log.debug("no flush because a request is running");
this._timer.initWithCallback(this, REQUEST_DELAY, this._timer.TYPE_ONE_SHOT);
}
CommandQueue.prototype.notify = function () {
try {
this._timer.cancel();
this.send();
} catch(e) {
log.exception(e);
}
}
CommandQueue.prototype.setSyncId = function() {
if( !this.serverSyncId || this.serverSyncId.length == 0 ) {
YOONO_PREFS.set('prevsyncid',YOONO_PREFS.get('syncid') || '', PREFS.PREF_STRING);
YOONO_PREFS.set('syncid', yoono.bkm.getSyncId(), PREFS.PREF_STRING);
} else {
YOONO_PREFS.set('prevsyncid',this.serverSyncId, PREFS.PREF_STRING);
YOONO_PREFS.set('syncid', this.serverSyncId, PREFS.PREF_STRING);
this.serverSyncId = "";
}
//yoono.bkm.dump();
}
CommandQueue.prototype._replaceSyncId = function (syncid) {
this.serverSyncId=syncid;
}
CommandQueue.prototype.nextPersistentCommandIsEmpty = function () {
return ( !this._nextTransactionFile.exists() || this._nextTransactionFile.fileSize<=4);
}
CommandQueue.prototype.send = function () {
if (this.isRunning)
return log.debug("Not sending, because a request is running");
var _this=this;
var requests=this._getRequest();
if (requests.length==0)
return log.debug("No more requests to send!");
this.isRunning=true;
// Encapsulate the request
if (!this._retryOnError)
this.setSyncId();
var xml = <server-script version="1.0"/>;
xml.appendChild( <context>
{(YOONO_PREFS.get('userid') ? <user-id> {YOONO_PREFS.get('userid')} </user-id> : '')}
{(YOONO_PREFS.get('syncid') ? <sync-id> {YOONO_PREFS.get('syncid')} </sync-id> : '')}
{(YOONO_PREFS.get('prevsyncid') ? <prev-sync-id> {YOONO_PREFS.get('prevsyncid')} </prev-sync-id> : '')}
<locale>{yoono.utils.getLocale()}</locale>
<version>{yoono.utils.getExtensionVersion()}</version>
<client>xpi</client>
</context>);
for each(var r in requests) {
xml.appendChild(r);
}
log.info('Sending async POST on ' + YOONO_PREFS.get('serverurl') + 'linkserver \n' + xml.toXMLString().replace(/<user-id>(.*)<\/user-id>/gi,"<user-id>*************</user-id>") + "\n>>>>>>>>>>>> ");
// Warm up ajax request
var data= 'script=' + encodeURIComponent( xml.toXMLString() );
var xmlhttp = CL["@mozilla.org/xmlextras/xmlhttprequest;1"].createInstance(CI.nsIXMLHttpRequest);
xmlhttp.open('POST', YOONO_PREFS.get('serverurl') + 'linkserver', true);
xmlhttp.setRequestHeader("Cache-Control", "no-cache");
xmlhttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
// Called on any type of error
function onError() {
try { xmlhttp.abort(); } catch(e) {}
for each(var o in _this._observers) {
try {
o.onRequestError(requests);
} catch(e) {
log.exception(e);
}
}
_this._retryOnError=true;
// Then try to resend the current request some times after
var delayFunction={
notify : function (t) {
_this.flush();
}
};
var timer = CL['@mozilla.org/timer;1'].createInstance(CI.nsITimer);
timer.initWithCallback(delayFunction, 6000, timer.TYPE_ONE_SHOT);
}
// Initialize a timer to timeout the request if necessary
var timeoutObserver = {
timer : CL['@mozilla.org/timer;1'].createInstance(CI.nsITimer),
delay : YOONO_PREFS.get('request.timeout') * 1000, // la pref est en secondes
start : function () {
this.timer.initWithCallback(this, this.delay, this.timer.TYPE_ONE_SHOT);
},
stop : function () {
this.timer.cancel();
},
notify : function (t) {
this.stop();
_this.isRunning=false;
onError();
}
};
// Called on success
xmlhttp.onload = function (event) {
try {
timeoutObserver.stop();
_this.isRunning=false;
if((4 != event.target.readyState) || (200 != event.target.status)) {
log.error(event.target.readyState+"/"+event.target.status);
return onError();
}
var data = new XML(xmlhttp.responseText.replace(/<\?xml.*?\?>\n?/g, ""));
log.info('Receiving response \n' + data.toXMLString() + "\n<<<<<<<<<<<<< ");
// Notify all observers and collect new requests
// all new requests are added to the running requests list
var redo=false;
for each(var o in _this._observers) {
var replace=false;
try {
replace = o.onRequestSuccess(requests,data);
} catch(e) {
log.exception(e);
}
if (replace) {
if (replace.overrideSyncId)
_this._replaceSyncId(replace.overrideSyncId);
_this._replaceRunningRequest(replace.xml);
redo=true;
break;
}
}
if (!redo)
_this._switchToNextRequests();
_this._retryOnError=false;
_this.flush();
} catch(e) {
log.exception(e);
}
};
// Called on network error
xmlhttp.onerror = function (e) { // Error
try {
timeoutObserver.stop();
_this.isRunning=false;
onError();
} catch(e) {
log.exception(e);
}
};
// Notify observers
for each(var o in this._observers) {
try {
o.onSendingRequest(requests);
} catch(e) {
log.exception(e);
}
}
// Go go go!
xmlhttp.send(data);
timeoutObserver.start();
}
var commandQueueMgr = new CommandQueue();